package combinations.hierarchical;

import attributes.HierarchicalAttributes;
import coalition.filters.HierarchicalCoalitionFilter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import utils.Util;

import combinations.Combinations;
import combinations.RawCombinations;

public class HierarchicalAttributeCombinations implements Combinations{

	HierarchicalCoalitionFilter hierarchicalCoalitionFilter;
	HierarchicalAttributes hierarchicalAttributes;
	
	public HierarchicalAttributeCombinations(HierarchicalCoalitionFilter hierarchicalCoalitionFilter ){
		this.hierarchicalCoalitionFilter = hierarchicalCoalitionFilter;
		hierarchicalAttributes = hierarchicalCoalitionFilter.getHierarchicalAttributes();
	}	
	
	Combinations rawCombinationsScheme = new RawCombinations();
	
	public List<List<Integer>> getCombinations(int n) {
		
		System.out.println("getCombinations: ");
		
		int totalAttributes = hierarchicalAttributes.getDictionary().size();
		
		//return rawCombinations.getCombinations(n);
		List<List<Integer>> rawCombinations = rawCombinationsScheme.getCombinations(totalAttributes);
		
		System.out.println("rawCombinations: "); 
		Util.printListOfListOfIntegers(rawCombinations);					
		
		List<List<Integer>> hierarchicalCombinations = new ArrayList<List<Integer>>();
		for(List<Integer> combination : rawCombinations){
			if(hierarchicalCoalitionFilter.keep(combination))
				hierarchicalCombinations.add(combination);
			else
				System.out.println("rejected combination:  " + Util.printListOfIntegers(combination));
		}
		List<List<Integer>> expandedCombinations = expandCombinations(hierarchicalCombinations);
		return expandedCombinations;		
	}	
	
	public List<List<Integer>> getCombinationsUpToSize(int n, int k) {
		
		System.out.println("getCombinationsUpToSize: ");
		
		//return rawCombinations.getCombinationsUpToSize(n, k);
		List<List<Integer>> rawCombinations = rawCombinationsScheme.getCombinationsUpToSize(n, k);
		List<List<Integer>> hierarchicalCombinations = new ArrayList<List<Integer>>();
		for(List<Integer> combination : rawCombinations){
			if(hierarchicalCoalitionFilter.keep(combination))
				hierarchicalCombinations.add(combination);
		}
		List<List<Integer>> expandedCombinations = expandCombinations(hierarchicalCombinations);
		return expandedCombinations;		
	}	
	
	private List<List<Integer>> expandCombinations(List<List<Integer>> combinations){
		List<List<Integer>> result = new ArrayList<List<Integer>>();
		for(List<Integer> combination : combinations)
			result.add(expand(combination));
		
		System.out.println("expanding combinations from: "); 
		Util.printListOfListOfIntegers(combinations);
		System.out.println("to: "); 
		Util.printListOfListOfIntegers(result);			
		
		return result;
	}
	
	private List<Integer> expand(List<Integer> combination){

		List<Integer> result = new ArrayList<Integer>();
		HashMap<Integer, Object> nodes = new HashMap<Integer, Object>();
		for(Integer node : combination){
			List<Integer> children = hierarchicalAttributes.getChildrenOfNode(node);
			for(Integer j : children){
				if(nodes.get(j) != null)
					throw new IllegalStateException("attributes in attribute combination have common children");
				nodes.put(j, new Object());
			}
		}
		for(Integer i : nodes.keySet())
			result.add(i);	
		
		return result;
	}
	
}
